package com.koushikdutta.async.http.server;

import android.annotation.TargetApi;
import android.text.TextUtils;
import com.koushikdutta.async.AsyncServer;
import com.koushikdutta.async.AsyncServerSocket;
import com.koushikdutta.async.AsyncSocket;
import com.koushikdutta.async.ByteBufferList;
import com.koushikdutta.async.DataEmitter;
import com.koushikdutta.async.NullDataCallback;
import com.koushikdutta.async.Util;
import com.koushikdutta.async.callback.CompletedCallback;
import com.koushikdutta.async.callback.ListenCallback;
import com.koushikdutta.async.http.HttpUtil;
import com.koushikdutta.async.http.WebSocket;
import com.koushikdutta.async.http.WebSocketImpl;
import com.koushikdutta.async.http.body.AsyncHttpRequestBody;
import com.koushikdutta.async.http.libcore.RawHeaders;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@TargetApi(5)
public class AsyncHttpServer {
    static final /* synthetic */ boolean $assertionsDisabled;
    private static Hashtable<Integer, String> mCodes = new Hashtable();
    static Hashtable<String, String> mContentTypes = new Hashtable();
    Hashtable<String, ArrayList<Pair>> mActions = new Hashtable();
    CompletedCallback mCompletedCallback;
    ListenCallback mListenCallback = new ListenCallback() {
        public void onAccepted(final AsyncSocket socket) {
            new AsyncHttpServerRequestImpl() {
                String fullPath;
                boolean hasContinued;
                Pair match;
                String path;
                boolean requestComplete;
                AsyncHttpServerResponseImpl res;
                boolean responseComplete;

                protected AsyncHttpRequestBody onUnknownBody(RawHeaders headers) {
                    return AsyncHttpServer.this.onUnknownBody(headers);
                }

                protected void onHeadersReceived() {
                    RawHeaders headers = getRawHeaders();
                    if (this.hasContinued || !"100-continue".equals(headers.get("Expect"))) {
                        String[] parts = headers.getStatusLine().split(" ");
                        this.fullPath = parts[1];
                        this.path = this.fullPath.split("\\?")[0];
                        this.method = parts[0];
                        synchronized (AsyncHttpServer.this.mActions) {
                            ArrayList<Pair> pairs = (ArrayList) AsyncHttpServer.this.mActions.get(this.method);
                            if (pairs != null) {
                                Iterator i$ = pairs.iterator();
                                while (i$.hasNext()) {
                                    Pair p = (Pair) i$.next();
                                    Matcher m = p.regex.matcher(this.path);
                                    if (m.matches()) {
                                        this.mMatcher = m;
                                        this.match = p;
                                        break;
                                    }
                                }
                            }
                        }
                        this.res = new AsyncHttpServerResponseImpl(socket, this) {
                            protected void onEnd() {
                                super.onEnd();
                                this.mSocket.setEndCallback(null);
                                AnonymousClass1.this.responseComplete = true;
                                AnonymousClass1.this.handleOnCompleted();
                            }
                        };
                        AsyncHttpServer.this.onRequest(this, this.res);
                        if (this.match == null) {
                            this.res.responseCode(404);
                            this.res.end();
                            return;
                        } else if (!getBody().readFullyOnRequest()) {
                            this.match.callback.onRequest(this, this.res);
                            return;
                        } else if (this.requestComplete) {
                            this.match.callback.onRequest(this, this.res);
                            return;
                        } else {
                            return;
                        }
                    }
                    pause();
                    Util.writeAll(this.mSocket, "HTTP/1.1 100 Continue\r\n\r\n".getBytes(), new CompletedCallback() {
                        public void onCompleted(Exception ex) {
                            AnonymousClass1.this.resume();
                            if (ex != null) {
                                AnonymousClass1.this.report(ex);
                                return;
                            }
                            AnonymousClass1.this.hasContinued = true;
                            AnonymousClass1.this.onHeadersReceived();
                        }
                    });
                }

                public void onCompleted(Exception e) {
                    if (this.res.getHeaders().getHeaders().getResponseCode() != 101) {
                        this.requestComplete = true;
                        super.onCompleted(e);
                        this.mSocket.setDataCallback(new NullDataCallback() {
                            public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
                                super.onDataAvailable(emitter, bb);
                                AnonymousClass1.this.mSocket.close();
                            }
                        });
                        handleOnCompleted();
                        if (getBody().readFullyOnRequest() && this.match != null) {
                            this.match.callback.onRequest(this, this.res);
                        }
                    }
                }

                private void handleOnCompleted() {
                    if (!this.requestComplete || !this.responseComplete) {
                        return;
                    }
                    if (HttpUtil.isKeepAlive(getHeaders().getHeaders())) {
                        AnonymousClass1.this.onAccepted(socket);
                    } else {
                        socket.close();
                    }
                }
            }.setSocket(socket);
            socket.resume();
        }

        public void onCompleted(Exception error) {
            AsyncHttpServer.this.report(error);
        }

        public void onListening(AsyncServerSocket socket) {
            AsyncHttpServer.this.mListeners.add(socket);
        }
    };
    ArrayList<AsyncServerSocket> mListeners = new ArrayList();

    public interface WebSocketRequestCallback {
        void onConnected(WebSocket webSocket, AsyncHttpServerRequest asyncHttpServerRequest);
    }

    private static class Pair {
        HttpServerRequestCallback callback;
        Pattern regex;

        private Pair() {
        }
    }

    static {
        boolean z;
        if (AsyncHttpServer.class.desiredAssertionStatus()) {
            z = false;
        } else {
            z = true;
        }
        $assertionsDisabled = z;
        mCodes.put(Integer.valueOf(200), "OK");
        mCodes.put(Integer.valueOf(206), "Partial Content");
        mCodes.put(Integer.valueOf(101), "Switching Protocols");
        mCodes.put(Integer.valueOf(301), "Moved Permanently");
        mCodes.put(Integer.valueOf(302), "Found");
        mCodes.put(Integer.valueOf(404), "Not Found");
    }

    public AsyncHttpServer() {
        mContentTypes.put("js", "application/javascript");
        mContentTypes.put("json", "application/json");
        mContentTypes.put("png", "image/png");
        mContentTypes.put("jpg", "image/jpeg");
        mContentTypes.put("html", "text/html");
        mContentTypes.put("css", "text/css");
        mContentTypes.put("mp4", "video/mp4");
        mContentTypes.put("mov", "video/quicktime");
        mContentTypes.put("wmv", "video/x-ms-wmv");
    }

    public void stop() {
        if (this.mListeners != null) {
            Iterator i$ = this.mListeners.iterator();
            while (i$.hasNext()) {
                ((AsyncServerSocket) i$.next()).stop();
            }
        }
    }

    protected void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
    }

    protected AsyncHttpRequestBody onUnknownBody(RawHeaders headers) {
        return new UnknownRequestBody(headers.get("Content-Type"));
    }

    public AsyncServerSocket listen(AsyncServer server, int port) {
        return server.listen(null, port, this.mListenCallback);
    }

    private void report(Exception ex) {
        if (this.mCompletedCallback != null) {
            this.mCompletedCallback.onCompleted(ex);
        }
    }

    public AsyncServerSocket listen(int port) {
        return listen(AsyncServer.getDefault(), port);
    }

    public void setErrorCallback(CompletedCallback callback) {
        this.mCompletedCallback = callback;
    }

    public void addAction(String action, String regex, HttpServerRequestCallback callback) {
        Pair p = new Pair();
        p.regex = Pattern.compile("^" + regex);
        p.callback = callback;
        synchronized (this.mActions) {
            ArrayList<Pair> pairs = (ArrayList) this.mActions.get(action);
            if (pairs == null) {
                pairs = new ArrayList();
                this.mActions.put(action, pairs);
            }
            pairs.add(p);
        }
    }

    public void websocket(String regex, WebSocketRequestCallback callback) {
        websocket(regex, null, callback);
    }

    public void websocket(String regex, final String protocol, final WebSocketRequestCallback callback) {
        get(regex, new HttpServerRequestCallback() {
            public void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
                boolean hasUpgrade = false;
                String connection = request.getHeaders().getHeaders().get("Connection");
                if (connection != null) {
                    for (String c : connection.split(",")) {
                        if ("Upgrade".equalsIgnoreCase(c.trim())) {
                            hasUpgrade = true;
                            break;
                        }
                    }
                }
                if ("websocket".equalsIgnoreCase(request.getHeaders().getHeaders().get("Upgrade")) && hasUpgrade) {
                    if (TextUtils.equals(protocol, request.getHeaders().getHeaders().get("Sec-WebSocket-Protocol"))) {
                        callback.onConnected(new WebSocketImpl(request, response), request);
                        return;
                    }
                    response.responseCode(404);
                    response.end();
                    return;
                }
                response.responseCode(404);
                response.end();
            }
        });
    }

    public void get(String regex, HttpServerRequestCallback callback) {
        addAction("GET", regex, callback);
    }

    public static String getResponseCodeDescription(int code) {
        String d = (String) mCodes.get(Integer.valueOf(code));
        if (d == null) {
            return "Unknown";
        }
        return d;
    }
}
